﻿using System;
using fastCSharp;
using fastCSharp.threading;
using System.IO;
using System.IO.Compression;

namespace diantou.web
{
    /// <summary>
    /// 文件上传
    /// </summary>
    [fastCSharp.code.cSharp.webCall(IsPool = true)]
    class upload : fastCSharp.code.cSharp.webCall.call<upload>
    {
        /// <summary>
        /// 回调开始
        /// </summary>
        private const string callbackStart = @"(""";
        /// <summary>
        /// 回调结束
        /// </summary>
        private const string callbackEnd = @""");" + fastCSharp.web.html.JsEnd;
        /// <summary>
        /// 头像上传
        /// </summary>
        /// <param name="callBack"></param>
        [fastCSharp.code.cSharp.webCall(IsOnlyPost = true)]
        public void Avatar(string callBack)
        {
            diantou.dataAccess.user user = pub.GetSessionUser(this);
            if (user != null)
            {
                string file = loadImage();
                if (file != null)
                {
                    diantou.dataAccess.tcpCall.user.reworkIcon(user.Id, file = file.Substring(WorkPath.Length).replace('\\', '/'), value => response(callBack, value.Type == fastCSharp.net.returnValue.type.Success && value.Value ? file : null));
                    return;
                }
            }
            response(callBack, null);
        }
        /// <summary>
        /// 企业图片上传
        /// </summary>
        /// <param name="callBack"></param>
        [fastCSharp.code.cSharp.webCall(IsOnlyPost = true)]
        public void Enterprise(string callBack)
        {
            diantou.dataAccess.user user = pub.GetSessionUser(this);
            if (user != null && user.IsEnterprisePermission)
            {
                string file = loadImage();
                if (file != null)
                {
                    diantou.dataAccess.tcpCall.user.reworkEnterpriseIcon(user.Id, file = file.Substring(WorkPath.Length).replace('\\', '/'), value => response(callBack, value.Type == fastCSharp.net.returnValue.type.Success && value.Value ? file : null));
                    return;
                }
            }
            response(callBack, null);
        }
        /// <summary>
        /// 话题图标上传
        /// </summary>
        /// <param name="topicId"></param>
        /// <param name="callBack"></param>
        [fastCSharp.code.cSharp.webCall(IsOnlyPost = true)]
        public void TopicIcon(int topicId, string callBack)
        {
            diantou.dataAccess.user user = pub.GetSessionUser(this);
            if (user != null)
            {
                string file = loadImage();
                if (file != null)
                {
                    diantou.dataAccess.tcpCall.topic.reworkIcon(topicId, user.Id, file = file.Substring(WorkPath.Length).replace('\\', '/'), value => response(callBack, value.Type == fastCSharp.net.returnValue.type.Success && value.Value ? file : null));
                    return;
                }
            }
            response(callBack, null);
        }
        /// <summary>
        /// 勋章图片
        /// </summary>
        /// <param name="callBack"></param>
        [fastCSharp.code.cSharp.webCall(IsOnlyPost = true)]
        public void Medal(string callBack)
        {
            diantou.dataAccess.user user = pub.GetSessionUser(this);
            if (user != null && user.Permission == dataModel.user.permission.Admin)
            {
                string file = loadImage();
                if (file != null)
                {
                    response(callBack, file.Substring(WorkPath.Length).replace('\\', '/'));
                    return;
                }
            }
            response(callBack, null);
        }
        /// <summary>
        /// 教程图片
        /// </summary>
        /// <param name="callBack"></param>
        [fastCSharp.code.cSharp.webCall(IsOnlyPost = true)]
        public void Tutorial(string callBack)
        {
            diantou.dataAccess.user user = pub.GetSessionUser(this);
            if (user != null && (user.Permission & dataModel.user.permission.TutorialEditor) != 0)
            {
                string file = loadImage();
                if (file != null)
                {
                    response(callBack, file.Substring(WorkPath.Length).replace('\\', '/'));
                    return;
                }
            }
            response(callBack, null);
        }
        /// <summary>
        /// 编辑框图片
        /// </summary>
        /// <param name="callBack"></param>
        [fastCSharp.code.cSharp.webCall(IsOnlyPost = true)]
        public void Editor(string callBack)
        {
            string file = null;
            diantou.dataAccess.user user = pub.GetSessionUser(this);
            if (user != null && (file = loadImage()) != null)
            {
                response(callBack, subString.Unsafe(file.replace('\\', '/'), WorkPath.Length));
            }
            else response(callBack, null);
        }
        /// <summary>
        /// 输出
        /// </summary>
        /// <param name="callBack"></param>
        /// <param name="value"></param>
        private void response(string callBack, subString value)
        {
            createResponse();
            try
            {
                response(fastCSharp.web.html.JsStart);
                response(callBack);
                response(callbackStart);
                response(value);
                response(callbackEnd);
            }
            finally { responseEnd(); }
        }
        /// <summary>
        /// 加载图片
        /// </summary>
        /// <returns></returns>
        private string loadImage()
        {
            foreach (fastCSharp.net.tcp.http.requestForm.value file in form.Files)
            {
                string fileName = LoadImage(WorkPath, file);
                if (fileName != null) return fileName;
            }
            return null;
        }
        /// <summary>
        /// 加载图片
        /// </summary>
        /// <param name="workPath"></param>
        /// <param name="file"></param>
        /// <returns></returns>
        internal static string LoadImage(string workPath, fastCSharp.net.tcp.http.requestForm.value file)
        {
            return file.SaveImage(createUploadPath(workPath) + ((ulong)date.NowSecond.Ticks).toHex16() + ((ulong)fastCSharp.pub.Identity).toHex16());
        }

        /// <summary>
        /// 上传测试数据
        /// </summary>
        /// <param name="callBack"></param>
        [fastCSharp.code.cSharp.webCall(IsOnlyPost = true, MaxPostDataSize = 5)]
        public unsafe void ProblemTestData(string callBack)
        {
            string value = null;
            diantou.dataAccess.user user = pub.GetSessionUser(this);
            if (user != null && (user.Permission & dataModel.user.permission.OnlineJudgeEditor) != 0 && form.Files.Count != 0)
            {
                fastCSharp.net.tcp.http.requestForm.value file = form.Files.UnsafeArray[0];
                if (file.SaveFileName == null)
                {
                    subArray<byte> data = file.Value;
                    if (data.Count > 3 && (BitConverter.ToInt32(data.UnsafeArray, data.StartIndex) & 0xffffffU) == fastCSharp.io.file.GetBom(diantou.dataAccess.problemTestData.UploadEncoding).Bom)
                    {
                        data.UnsafeSet(data.StartIndex + 3, data.Count - 3);
                    }
                    value = diantou.dataAccess.problemTestData.UploadEncoding.GetString(data.UnsafeArray, data.StartIndex, data.Count);
                }
                else
                {
                    value = File.ReadAllText(file.SaveFileName, diantou.dataAccess.problemTestData.UploadEncoding);
                }
                fixed (char* valueFixed = value.replace((char)0, ' '))
                {
                    using (charStream charStream = new fastCSharp.charStream(valueFixed, value.Length))
                    {
                        charStream.UnsafeAddLength(value.Length);
                        value = fastCSharp.web.ajax.FormatJavascript(charStream);
                    }
                }
            }
            response(callBack, value);
        }
        /// <summary>
        /// 上传测试数据
        /// </summary>
        /// <param name="callBack"></param>
        /// <param name="problemId"></param>
        [fastCSharp.code.cSharp.webCall(IsOnlyPost = true, MaxPostDataSize = 10)]
        public void TestData(string callBack, int problemId)
        {
            diantou.dataAccess.user user = pub.GetSessionUser(this);
            if (user != null && (user.Permission & dataModel.user.permission.OnlineJudgeEditor) != 0 && form.Files.Count != 0)
            {
                fastCSharp.net.tcp.http.requestForm.value file = form.Files.UnsafeArray[0];
                diantou.dataAccess.tcpCall.problemTestData.uploadZip(problemId, file.SaveFileName == null ? file.Value.ToArray() : File.ReadAllBytes(file.SaveFileName), user.Id, value => response(callBack, value.Type == fastCSharp.net.returnValue.type.Success && value.Value.Value != 0 ? problemId : 0));
                return;
            }
            response(callBack, 0);
        }
        /// <summary>
        /// 输出
        /// </summary>
        /// <param name="callBack"></param>
        /// <param name="value"></param>
        private void response(string callBack, int problemId)
        {
            createResponse();
            try
            {
                response(fastCSharp.web.html.JsStart);
                response(callBack);
                response(subString.Unsafe(callbackStart, 0, callbackStart.Length - 1));
                response(problemId.toString());
                response(subString.Unsafe(callbackEnd, 1));
            }
            finally { responseEnd(); }
        }
        /// <summary>
        /// 上传测试数据
        /// </summary>
        /// <param name="token"></param>
        /// <param name="problemId"></param>
        [fastCSharp.code.cSharp.webCall(IsOnlyPost = true, MaxPostDataSize = 10)]
        public void ReworkTestData(string token, int problemId)
        {
            diantou.dataAccess.user user = diantou.dataAccess.tcpCall.user.GetToken(token);
            if (user == null) responseApi(new fastCSharp.openApi._51nod.returnValue<int>.value { ReturnCode = fastCSharp.openApi._51nod.returnCode.TokenError });
            else if ((user.Permission & dataModel.user.permission.OnlineJudgeEditor) == 0) responseApi(new fastCSharp.openApi._51nod.returnValue<int>.value { ReturnCode = fastCSharp.openApi._51nod.returnCode.PermissionError });
            else if (form.Files.Count == 0) responseApi(new fastCSharp.openApi._51nod.returnValue<int>.value { ReturnCode = fastCSharp.openApi._51nod.returnCode.NotFoundUploadFile });
            else
            {
                try
                {
                    fastCSharp.net.tcp.http.requestForm.value file = form.Files.UnsafeArray[0];
                    diantou.dataAccess.tcpCall.problemTestData.uploadZip(problemId, file.SaveFileName == null ? file.Value.ToArray() : File.ReadAllBytes(file.SaveFileName), user.Id, onReworkTestData);
                    return;
                }
                catch (Exception error)
                {
                    log.Default.Add(error, null, false);
                }
                responseApi(new fastCSharp.openApi._51nod.returnValue<int>.value { ReturnCode = fastCSharp.openApi._51nod.returnCode.ServerError });
            }
        }
        /// <summary>
        /// 上传测试数据回调处理
        /// </summary>
        /// <param name="value"></param>
        private void onReworkTestData(fastCSharp.net.returnValue<fastCSharp.openApi._51nod.returnValue<int>.value> value)
        {
            responseApi(value.Value);
        }
        /// <summary>
        /// 上传考试图片
        /// </summary>
        /// <param name="callBack"></param>
        [fastCSharp.code.cSharp.webCall(IsOnlyPost = true)]
        public void ExamImage(string callBack, int examId, diantou.dataModel.examQuestionBase.type questionType)
        {
            diantou.dataAccess.user user = pub.GetSessionUser(this);
            if (user != null)
            {
                string file = loadImage();
                if (file != null)
                {
                    diantou.examDataAccess.tcpCall.exam.reworkImage(examId, user.Id, file = file.Substring(WorkPath.Length).replace('\\', '/'), value => response(callBack, value.Type == fastCSharp.net.returnValue.type.Success && value.Value ? file : null));
                    return;
                }
            }
            response(callBack, null);
        }
        /// <summary>
        /// 上传考试题目
        /// </summary>
        /// <param name="callBack"></param>
        [fastCSharp.code.cSharp.webCall(IsOnlyPost = true, MaxPostDataSize = 8)]
        public void ExamQuestion(string callBack, diantou.dataModel.examQuestionBase.type questionType)
        {
            diantou.dataAccess.user user = pub.GetSessionUser(this);
            if (user != null && (user.Permission & dataModel.user.permission.ExamEditor) != 0 && form.Files.Count != 0)
            {
                fastCSharp.net.tcp.http.requestForm.value file = form.Files.UnsafeArray[0];
                diantou.examDataAccess.tcpCall.examQuestion.uploadZip(file.SaveFileName == null ? file.Value.ToArray() : File.ReadAllBytes(file.SaveFileName), questionType, user.Id, value =>
                {
                    if (value.Type == fastCSharp.net.returnValue.type.Success)
                    {
                        createResponse();
                        try
                        {
                            response(fastCSharp.web.html.JsStart);
                            response(callBack);
                            response(subString.Unsafe(callbackStart, 0, callbackStart.Length - 1));
                            response(value.Value.Total.toString());
                            response(',');
                            response(value.Value.New.toString());
                            response(',');
                            response(value.Value.Update.toString());
                            response(subString.Unsafe(callbackEnd, 1));
                        }
                        finally { responseEnd(); }
                    }
                    else this.response(callBack, 0);
                });
                return;
            }
            this.response(callBack, 0);
        }
        /// <summary>
        /// 上传考试用户
        /// </summary>
        /// <param name="callBack"></param>
        /// <param name="examId"></param>
        [fastCSharp.code.cSharp.webCall(IsOnlyPost = true, MaxPostDataSize = 8)]
        public void ExamUser(string callBack, int examId)
        {
            diantou.dataAccess.user user = pub.GetSessionUser(this);
            if (user != null && form.Files.Count != 0)
            {
                fastCSharp.net.tcp.http.requestForm.value file = form.Files.UnsafeArray[0];
                diantou.examDataAccess.tcpCall.examUser.uploadZip(examId, file.SaveFileName == null ? file.Value.ToArray() : File.ReadAllBytes(file.SaveFileName), user.Id, value => response(callBack, value.Type == fastCSharp.net.returnValue.type.Success ? value.Value : 0));
                return;
            }
            response(callBack, 0);
        }
        /// <summary>
        /// 头像考试用户上传
        /// </summary>
        /// <param name="callBack"></param>
        [fastCSharp.code.cSharp.webCall(IsOnlyPost = true)]
        public void ExamUserIcon(string callBack)
        {
            diantou.examDataAccess.examUser user = pub.GetSessionExamUser(this);
            if (user != null)
            {
                string file = loadImage();
                if (file != null)
                {
                    diantou.examDataAccess.tcpCall.examUser.reworkIcon(user.Id, file = file.Substring(WorkPath.Length).replace('\\', '/'), value => response(callBack, value.Type == fastCSharp.net.returnValue.type.Success && value.Value ? file : null));
                    return;
                }
            }
            response(callBack, null);
        }
        /// <summary>
        /// 头像考试邀请用户上传
        /// </summary>
        /// <param name="callBack"></param>
        [fastCSharp.code.cSharp.webCall(IsOnlyPost = true)]
        public void ExamInvitationIcon(string callBack)
        {
            int id = pub.GetExamInvitationId(this);
            if (id != 0)
            {
                string file = loadImage();
                if (file != null)
                {
                    response(callBack, file.Substring(WorkPath.Length).replace('\\', '/'));
                    return;
                }
            }
            response(callBack, null);
        }
        /// <summary>
        /// 考试用户上传头像(完成答卷后发简历的考试)
        /// </summary>
        /// <param name="callBack"></param>
        [fastCSharp.code.cSharp.webCall(IsOnlyPost = true)]
        public void ExamUserIconMobileCode(string callBack, int examId, long mobile, uint mobileCode)
        {
            string file = loadImage();
            if (file != null)
            {
                diantou.examDataAccess.tcpCall.examUser.checkMobileCode(examId, mobile, mobileCode, value => response(callBack, value.Value ? file.Substring(WorkPath.Length).replace('\\', '/') : null));
                return;
            }
            response(callBack, null);
        }
        /// <summary>
        /// 上传考试简历
        /// </summary>
        /// <param name="callBack"></param>
        [fastCSharp.code.cSharp.webCall(IsOnlyPost = true)]
        public void ExamResume(string callBack)
        {
            diantou.examDataAccess.examUser user = pub.GetSessionExamUser(this);
            if (user != null)
            {
                string extensionName = null;
                foreach (fastCSharp.net.tcp.http.requestForm.value file in form.Files)
                {
                    subArray<byte> extensionNameData = file.ExtensionName;
                    switch (extensionNameData.Count)
                    {
                        case 3:
                            int value = fastCSharp.unsafer.memory.GetInt(extensionNameData.UnsafeArray, extensionNameData.StartIndex) & 0xffffff | 0x202020;
                            if (value == 'd' + ('o' << 8) + ('c' << 16)) extensionName = ".doc";
                            else if (value == 'p' + ('d' << 8) + ('f' << 16)) extensionName = ".pdf";
                            break;
                        case 4:
                            if ((fastCSharp.unsafer.memory.GetInt(extensionNameData.UnsafeArray, extensionNameData.StartIndex) | 0x20202020) == 'd' + ('o' << 8) + ('c' << 16) + ('x' << 24))
                            {
                                extensionName = ".docx";
                            }
                            break;
                    }
                    if (extensionName != null)
                    {
                        string fileName = createUploadPath(WorkPath) + "examResume" + user.ToString() + extensionName;
                        file.SaveFile(fileName, true);
                        diantou.examDataAccess.tcpCall.examUser.reworkResume(user.Id, fileName.Substring(WorkPath.Length), value => response(callBack, value.Value ? user.Id : 0));
                        return;
                    }
                }
            }
            response(callBack, null);
        }
        /// <summary>
        /// 输出
        /// </summary>
        /// <param name="value"></param>
        private void responseApi(fastCSharp.openApi._51nod.returnValue<int>.value value)
        {
            createResponse();
            try
            {
                response(new fastCSharp.code.cSharp.tcpBase.parameterJsonToSerialize<fastCSharp.openApi._51nod.returnValue<int>.value> { Return = value }.ToJson());
            }
            finally { responseEnd(); }
        }
        /// <summary>
        /// 当前工作路径
        /// </summary>
        private static string currentWorkPath;
        /// <summary>
        /// 当前日期路径
        /// </summary>
        private static int currentDatePath;
        /// <summary>
        /// 当前上传路径
        /// </summary>
        private static string currentUploadPath;
        /// <summary>
        /// 上传目录访问锁
        /// </summary>
        private static int uploadPathLock;
        /// <summary>
        /// 创建上传目录
        /// </summary>
        /// <param name="workPath"></param>
        /// <returns></returns>
        private static string createUploadPath(string workPath)
        {
            string path;
            int dataPath = date.NowSecond.toInt();
            interlocked.CompareSetYield(ref uploadPathLock);
            if (currentWorkPath == workPath && dataPath == currentDatePath)
            {
                path = currentUploadPath;
                uploadPathLock = 0;
                return path;
            }
            uploadPathLock = 0;
            path = workPath + @"upload\" + ((uint)dataPath).toHex8() + @"\";
            try
            {
                if (!Directory.Exists(path)) Directory.CreateDirectory(path);
                interlocked.CompareSetYield(ref uploadPathLock);
                currentWorkPath = workPath;
                currentDatePath = dataPath;
                currentUploadPath = path;
                uploadPathLock = 0;
                return path;
            }
            catch (Exception error)
            {
                log.Default.Add(error, null, true);
            }
            return null;
        }
    }
}
